// 基于 SnowLang Project (https://gitee.com/jcnc-org/snow) 的衍生作品
// 原始版权归属: Copyright © 2025 Ke Xu (Luke)
// 本实现版权归属: Copyright © 2025 Sany
// 遵循 Apache License 2.0 授权
package factories

import (
	"errors"

	"gitee.com/xntk2381/cc/vm/commands/flow"
	"gitee.com/xntk2381/cc/vm/commands/register"
	"gitee.com/xntk2381/cc/vm/commands/stack"
	"gitee.com/xntk2381/cc/vm/commands/system"
	"gitee.com/xntk2381/cc/vm/commands/type/control"
	"gitee.com/xntk2381/cc/vm/commands/type/conversion"
	"gitee.com/xntk2381/cc/vm/engine/opcode"
	"gitee.com/xntk2381/cc/vm/interfaces"
)

// 定义命令表大小
const commandTableSize = 0x0500

var commands [commandTableSize]interfaces.Command

/**
 * The CommandFactory class is responsible
 * for getting the corresponding instruction instance based on the operation code.
 * <p>This class uses an array for fast, constant-time access to corresponding command instances.</p>
 */

func init() {
	// region Type Control (0x0000-0x00BF)
	// region Byte8	 (0x0000-0x001F)
	commands[opcode.B_ADD] = control.BAddCommand{}
	commands[opcode.B_SUB] = control.BSubCommand{}
	commands[opcode.B_MUL] = control.BMulCommand{}
	commands[opcode.B_DIV] = control.BDivCommand{}
	commands[opcode.B_MOD] = control.BModCommand{}
	commands[opcode.B_NEG] = control.BNegCommand{}
	commands[opcode.B_INC] = control.BIncCommand{}

	commands[opcode.B_AND] = control.BAndCommand{}
	commands[opcode.B_OR] = control.BOrCommand{}
	commands[opcode.B_XOR] = control.BXorCommand{}

	commands[opcode.B_PUSH] = control.BPushCommand{}
	commands[opcode.B_LOAD] = control.BLoadCommand{}
	commands[opcode.B_STORE] = control.BStoreCommand{}

	commands[opcode.B_CE] = control.BCECommand{}
	commands[opcode.B_CNE] = control.BCNECommand{}
	commands[opcode.B_CG] = control.BCGCommand{}
	commands[opcode.B_CGE] = control.BCGECommand{}
	commands[opcode.B_CL] = control.BCLCommand{}
	commands[opcode.B_CLE] = control.BCLECommand{}

	// endregion

	// region Short16 (0x0020-0x003F)
	commands[opcode.S_ADD] = control.SAddCommand{}
	commands[opcode.S_SUB] = control.SSubCommand{}
	commands[opcode.S_MUL] = control.SMulCommand{}
	commands[opcode.S_DIV] = control.SDivCommand{}
	commands[opcode.S_MOD] = control.SModCommand{}
	commands[opcode.S_NEG] = control.SNegCommand{}
	commands[opcode.S_INC] = control.SIncCommand{}

	commands[opcode.S_AND] = control.SAndCommand{}
	commands[opcode.S_OR] = control.SOrCommand{}
	commands[opcode.S_XOR] = control.SXorCommand{}

	commands[opcode.S_PUSH] = control.SPushCommand{}
	commands[opcode.S_LOAD] = control.SLoadCommand{}
	commands[opcode.S_STORE] = control.SStoreCommand{}

	commands[opcode.S_CE] = control.SCECommand{}
	commands[opcode.S_CNE] = control.SCNECommand{}
	commands[opcode.S_CG] = control.SCGCommand{}
	commands[opcode.S_CGE] = control.SCGECommand{}
	commands[opcode.S_CL] = control.SCLCommand{}
	commands[opcode.S_CLE] = control.SCLECommand{}
	// endregion

	// region Int32 (0x0040-0x005F)
	commands[opcode.I_ADD] = control.IAddCommand{}
	commands[opcode.I_SUB] = control.ISubCommand{}
	commands[opcode.I_MUL] = control.IMulCommand{}
	commands[opcode.I_DIV] = control.IDivCommand{}
	commands[opcode.I_MOD] = control.IModCommand{}
	commands[opcode.I_NEG] = control.INegCommand{}
	commands[opcode.I_INC] = control.IIncCommand{}

	commands[opcode.I_AND] = control.IAndCommand{}
	commands[opcode.I_OR] = control.IOrCommand{}
	commands[opcode.I_XOR] = control.IXorCommand{}

	commands[opcode.I_PUSH] = control.IPushCommand{}
	commands[opcode.I_LOAD] = control.ILoadCommand{}
	commands[opcode.I_STORE] = control.IStoreCommand{}

	commands[opcode.I_CE] = control.ICECommand{}
	commands[opcode.I_CNE] = control.ICNECommand{}
	commands[opcode.I_CG] = control.ICGCommand{}
	commands[opcode.I_CGE] = control.ICGECommand{}
	commands[opcode.I_CL] = control.ICLCommand{}
	commands[opcode.I_CLE] = control.ICLECommand{}
	// endregion

	// region Long64 (0x0060-0x007F)
	commands[opcode.L_ADD] = control.LAddCommand{}
	commands[opcode.L_SUB] = control.LSubCommand{}
	commands[opcode.L_MUL] = control.LMulCommand{}
	commands[opcode.L_DIV] = control.LDivCommand{}
	commands[opcode.L_MOD] = control.LModCommand{}
	commands[opcode.L_NEG] = control.LNegCommand{}
	commands[opcode.L_INC] = control.LIncCommand{}

	commands[opcode.L_AND] = control.LAndCommand{}
	commands[opcode.L_OR] = control.LOrCommand{}
	commands[opcode.L_XOR] = control.LXorCommand{}

	commands[opcode.L_PUSH] = control.LPushCommand{}
	commands[opcode.L_LOAD] = control.LLoadCommand{}
	commands[opcode.L_STORE] = control.LStoreCommand{}

	commands[opcode.L_CE] = control.LCECommand{}
	commands[opcode.L_CNE] = control.LCNECommand{}
	commands[opcode.L_CG] = control.LCGCommand{}
	commands[opcode.L_CGE] = control.LCGECommand{}
	commands[opcode.L_CL] = control.LCLCommand{}
	commands[opcode.L_CLE] = control.LCLECommand{}
	// endregion

	// region Float32 (0x0080-0x009F)
	commands[opcode.F_ADD] = control.FAddCommand{}
	commands[opcode.F_SUB] = control.FSubCommand{}
	commands[opcode.F_MUL] = control.FMulCommand{}
	commands[opcode.F_DIV] = control.FDivCommand{}
	commands[opcode.F_MOD] = control.FModCommand{}
	commands[opcode.F_NEG] = control.FNegCommand{}
	commands[opcode.F_INC] = control.FIncCommand{}

	commands[opcode.F_PUSH] = control.FPushCommand{}
	commands[opcode.F_LOAD] = control.FLoadCommand{}
	commands[opcode.F_STORE] = control.FStoreCommand{}

	commands[opcode.F_CE] = control.FCECommand{}
	commands[opcode.F_CNE] = control.FCNECommand{}
	commands[opcode.F_CG] = control.FCGCommand{}
	commands[opcode.F_CGE] = control.FCGECommand{}
	commands[opcode.F_CL] = control.FCLCommand{}
	commands[opcode.F_CLE] = control.FCLECommand{}
	// endregion

	// region Double64 (0x00A0-0x00BF)
	commands[opcode.D_ADD] = control.DAddCommand{}
	commands[opcode.D_SUB] = control.DSubCommand{}
	commands[opcode.D_MUL] = control.DMulCommand{}
	commands[opcode.D_DIV] = control.DDivCommand{}
	commands[opcode.D_MOD] = control.DModCommand{}
	commands[opcode.D_NEG] = control.DNegCommand{}
	commands[opcode.D_INC] = control.DIncCommand{}

	commands[opcode.D_PUSH] = control.DPushCommand{}
	commands[opcode.D_LOAD] = control.DLoadCommand{}
	commands[opcode.D_STORE] = control.DStoreCommand{}

	commands[opcode.D_CE] = control.DCECommand{}
	commands[opcode.D_CNE] = control.DCNECommand{}
	commands[opcode.D_CG] = control.DCGCommand{}
	commands[opcode.D_CGE] = control.DCGECommand{}
	commands[opcode.D_CL] = control.DCLCommand{}
	commands[opcode.D_CLE] = control.DCLECommand{}
	// endregion
	// endregion

	// region Type Conversion (0x00C0-0x00DF)
	commands[opcode.I2L] = conversion.I2LCommand{}
	commands[opcode.I2S] = conversion.I2SCommand{}
	commands[opcode.I2B] = conversion.I2BCommand{}
	commands[opcode.I2D] = conversion.I2DCommand{}
	commands[opcode.I2F] = conversion.I2FCommand{}

	commands[opcode.L2I] = conversion.L2ICommand{}
	commands[opcode.L2D] = conversion.L2DCommand{}
	commands[opcode.L2F] = conversion.L2FCommand{}

	commands[opcode.F2I] = conversion.F2ICommand{}
	commands[opcode.F2L] = conversion.F2LCommand{}
	commands[opcode.F2D] = conversion.F2DCommand{}

	commands[opcode.D2I] = conversion.D2ICommand{}
	commands[opcode.D2L] = conversion.D2LCommand{}
	commands[opcode.D2F] = conversion.D2FCommand{}

	commands[opcode.S2I] = conversion.S2ICommand{}
	commands[opcode.B2I] = conversion.B2ICommand{}
	// endregion

	// region Stack Control (0x0100-0x01FF)
	commands[opcode.POP] = stack.PopCommand{}
	commands[opcode.DUP] = stack.DupCommand{}
	commands[opcode.SWAP] = stack.SwapCommand{}
	// endregion

	// region Flow Control (0x0200-0x02FF)
	commands[opcode.JUMP] = flow.JumpCommand{}
	commands[opcode.CALL] = flow.CallCommand{}
	commands[opcode.RET] = flow.RetCommand{}
	// endregion

	// region Register Control (0x0300-0x03FF)
	commands[opcode.MOV] = register.MovCommand{}
	// endregion

	// region  System Control (0x0400-0x04FF)
	commands[opcode.HALT] = system.HaltCommand{}
	//        commands[opcode.SYSCALL]     = new SyscallCommand();
	//        commands[opcode.DEBUG_TRAP]  = new DebugTrapCommand();
	// endregion

}

/**
 * Retrieves the corresponding command instance based on the operation code.
 * <p>This method looks up the given operation code and returns the corresponding command instance.</p>
 *
 * @param opCode The operation code (instruction code)
 * @return An Optional containing the command object. If a command exists for the operation code, it returns the command instance; otherwise, an empty Optional is returned.
 */
func GetInstruction(opCode int) (interfaces.Command, error) {
	if opCode >= 0 && opCode < len(commands) {
		if cmd := commands[opCode]; cmd != nil {
			return cmd, nil
		}
		return nil, errors.New("unknown instruction")
	}
	return nil, errors.New("opcode out of range")
}
